#include <tcl.h>
// #include <windows.h>
// #include <stdio.h>
// #include <stdlib.h>
#include <netsnmptcl.h>
#include <unistd.h>
// #include <net-snmp/library/default_store.h>
#define BUFFER_SIZE 248000


// void StdOut(char *msg);
// void StdErr(char *msg);
// char tcl_msg_buf[102400];



static Tcl_Interp *tclInterp;	// handle to active TCL interpreter


static int dump_option()
{
	int i;
	printf("\nBoolean\n");
	for (i=0;i<48;i++)
		printf("%d ",netsnmp_ds_get_boolean(0,i));		
	// printf("\nInteger\n");
	// for (i=0;i<48;i++)
		// printf("%d ",netsnmp_ds_get_int(0,i));
	// printf("\nString\n");
	// for (i=0;i<48;i++)
		// printf("%s ",netsnmp_ds_get_string(0,i));	
	printf("\n");	
}

static int stderr_save,stdout_save;


// redirect stderr message to buffer
// print buffer result to tcl interpreter

static int start_buffer_stderr(char *buferr)
{	
	fflush(stderr); //clean everything first
	
	stderr_save = dup(STDERR_FILENO); //save the stderr state
	
	freopen("NUL", "a", stderr); //redirect stderr to null pointer
	
	setvbuf(stderr, buferr, _IOFBF, BUFFER_SIZE); //set buffer to stderr
	
	return 0;
}

static int stop_buffer_stderr()
{
	freopen("NUL", "a", stderr); //redirect stdout to null again
	
	dup2(stderr_save, STDERR_FILENO); //restore the previous state of stdout
	
	setvbuf(stderr, NULL, _IONBF, 50); //disable buffer to print to screen instantly
	
	return 0;
}


static int snmp_get(
	ClientData clientdata,
	Tcl_Interp *interp,
	int argc, 
	const char **argv)
{	
	// snmp_close_sessions();
	// clear_sec_mod();
	// shutdown_secmod();
	// snmp_shutdown("snmpapp");
	// char new_buf_err[BUFFER_SIZE]={'\0'};
	// start_buffer_stderr(new_buf_err);

	if (snmpget(argc, argv))
	{
		// stop_buffer_stderr();
		// StdErr(new_buf_err);
		return TCL_ERROR;
	}
	// stop_buffer_stderr();
	return TCL_OK;
}



static int snmp_getnext(
	ClientData clientdata,
	Tcl_Interp *interp,
	int argc, 
	const char **argv)
{
	// snmp_shutdown("snmpapp");
	if (snmpgetnext(argc, argv))
		return TCL_ERROR;

	return TCL_OK;
}


static int snmp_walk(
	ClientData clientdata,
	Tcl_Interp *interp,
	int argc, 
	const char **argv)
{
	// snmp_shutdown("snmpapp");
	if (snmpwalk(argc, argv))
		return TCL_ERROR;

	return TCL_OK;
}



static int snmp_set(
	ClientData clientdata,
	Tcl_Interp *interp,
	int argc, 
	const char **argv)
{
	// snmp_shutdown("snmpapp");
	if (snmpset(argc, argv))
		return TCL_ERROR;

	return TCL_OK;
}

static int snmp_translate(
	ClientData clientdata,
	Tcl_Interp *interp,
	int argc, 
	const char **argv)
{
	// snmp_shutdown("snmpapp");
	if (snmptranslate(argc, argv))
		return TCL_ERROR;

	return TCL_OK;
}

static int snmp_bulkget(
	ClientData clientdata,
	Tcl_Interp *interp,
	int argc, 
	const char **argv)
{
	// snmp_shutdown("snmpapp");
	if (snmpbulkget(argc, argv))
		return TCL_ERROR;

	return TCL_OK;
}

static int snmp_bulkwalk(
	ClientData clientdata,
	Tcl_Interp *interp,
	int argc, 
	const char **argv)
{
	// snmp_shutdown("snmpapp");
	if (snmpbulkwalk(argc, argv))
		return TCL_ERROR;

	return TCL_OK;
}


static void usage() 
{
	printf("USAGE: snmp_loadmib [OPTIONS]\n");
	printf("\t-h                    display this help message\n");
	printf("\t-m MIB[:...]          load given list of MIBs (ALL loads everything)\n");
	printf("\t-M DIR[:...]          look in given list of directories for MIBs\n");
	return;
}

static int snmp_loadmib(
	ClientData clientdata,
	Tcl_Interp *interp,
	int argc, 
	const char **argv)
{
	int arg;	
	extern int optreset;
	optind = 1;
	opterr = 1;
	optreset=1;
	
	snmp_shutdown("snmpapp");
	while ((arg = getopt(argc,(char **) argv, "hm:M:")) != EOF) {
		switch (arg) {
        case 'h':
            usage();
            return TCL_ERROR;
        case 'm':
            setenv("MIBS", optarg, 1);
            break;
        case 'M':
            setenv("MIBDIRS", optarg, 1);
			// netsnmp_get_mib_directory(); /* prepare the default directories */
            netsnmp_set_mib_directory(optarg);
            break;
		default:
			usage();
			return TCL_ERROR;
			break;
		}
	}	
	// printf("qqq %s\n",netsnmp_get_mib_directory());
	// printf("qqq %s\n",getenv("MIBS"));
	if (!getenv("MIBDIRS")) {		
		netsnmp_set_mib_directory("/usr/share/snmp/mibs");
	}
	if (!getenv("MIBS"))
		setenv("MIBS", "all");
	// printf("qqq %s\n",getenv("MIBS"));	
	// setenv("MIBS", "all");
	// netsnmp_set_mib_directory(argv[1]);
	// init_snmp("snmpapp")
	// netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SAVE_MIB_DESCRS,1);
	netsnmp_ds_set_boolean(0, 1,1);
	netsnmp_init_mib();		
	return TCL_OK;
}

#ifdef  __cplusplus
extern  "C"
#endif 
int DLLEXPORT
Netsnmptcl_Init(Tcl_Interp *interp)
{
	if (Tcl_InitStubs(interp, "8.4", 0) == NULL) {
		return TCL_ERROR;
	}
	/* changed this to check for an error - GPS */
	if (Tcl_PkgProvide(interp, "netsnmptcl", "1.0") == TCL_ERROR) {
		return TCL_ERROR;
	}

	tclInterp = interp;
	Tcl_CreateCommand(interp, "snmp_get"      , snmp_get        ,NULL,NULL);
	Tcl_CreateCommand(interp, "snmp_getnext"  , snmp_getnext    ,NULL,NULL);
	Tcl_CreateCommand(interp, "snmp_translate", snmp_translate  ,NULL,NULL);
	Tcl_CreateCommand(interp, "snmp_walk"     , snmp_walk       ,NULL,NULL);
	Tcl_CreateCommand(interp, "snmp_set"      , snmp_set        ,NULL,NULL);
	Tcl_CreateCommand(interp, "snmp_bulkget"  , snmp_bulkget    ,NULL,NULL);
	Tcl_CreateCommand(interp, "snmp_bulkwalk" , snmp_bulkwalk   ,NULL,NULL);
	Tcl_CreateCommand(interp, "snmp_loadmib"  , snmp_loadmib    ,NULL,NULL);
	// Tcl_CreateObjCommand(interp, "Jimmy_oo", OO,NULL,NULL);
	// Tcl_CreateCommand(interp, "visa_open", (Tcl_CmdProc *)VISA_Open,(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
	return TCL_OK;
}

//----------------------------------------------------------------------------
// Low level function to output messages to standard output channel.
//
// Returns none.
//
void StdOut(char *msg)
{
	// If TCL interpreter is available, then append this message to TCL
	// result string. Otherwise use message boxes.
	if (tclInterp) {
		// Tcl_AppendResult(tclInterp, msg, NULL);
		Tcl_AppendElement (tclInterp, msg);
		tcl_msg_buf[0]='\0';
//		Tcl_SetResult(tclInterp, msg, TCL_STATIC);
//	    Tcl_FreeResult(tclInterp);
	}
}


//----------------------------------------------------------------------------
// Low level function to output messages to standard error channel.
//
// Returns none.
//
void StdErr(char *msg)
{	
	Tcl_AppendResult(tclInterp, msg, NULL);
	tcl_msg_buf[0]='\0';
	// sprintf(tclInterp->result, msg);
	// StdOut(msg);
}
